package com.gxa.hualianeshop.shiro;

import com.gxa.hualianeshop.common.util.JwtUtil;
import com.gxa.hualianeshop.entity.pojo.Menu;
import com.gxa.hualianeshop.entity.vo.EmplVO;
import com.gxa.hualianeshop.entity.vo.RoleVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.util.List;

/**
 * shiro认证和授权的实现
 * @author bill
 * @date 2023/7/6 15:06
 */

@Slf4j
@Component
public class EmplRealm extends AuthorizingRealm {

    //Realm要支持自定义的JwtToken, 需要重写support方法
    /**
     * 重写支持自定义token的方法
     * @param token Subject在login的时候提供的token对象
     * @return true表示支持该token
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken ;
    }

    /**
     * 执行认证流程
     * @param token Subject执行login认证的时候传的参数信息
     * @return 认证封装信息对象
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        Object jwt = token.getPrincipal();

        //如果jwt为空,直接返回null ,触发shiro异常信息
        if(StringUtils.isEmpty(jwt)){
            return null;
        }

        // 取出phone的载荷信息
        String phone = JwtUtil.getClaim(jwt.toString(), "phone");

        // 校验JWT的合法性
        boolean success = JwtUtil.verify(jwt.toString(), "phone", phone);

        if(success){
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(jwt,jwt,getName());
            return info;
        }

        return null;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        // 用户的授权信息通过远程调用(empl-service 8000)
        // 返回EmplVo

        RestTemplate restTemplate =new RestTemplate();
        // FIXME: 请求参数应该用当前shiro获取的用户信息: phone
        String url = "http://localhost:8000/empl/getPermsById?id=1";

        EmplVO emplVO = restTemplate.getForObject(url, EmplVO.class);
        log.info("emplVO:"+emplVO);

        // TODO: 从vo对象中读取所有的角色(foreach) , 从每个角色中读取menu(foreach)
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        List<RoleVO> roleVOList = emplVO.getRoleVOList();
        for (RoleVO roleVO : roleVOList) {

            // 把角色名获取, 用于和@RequiresRoles中的角色比较
            info.addRole(roleVO.getRoleName());

            // 从角色中获取所有的权限信息
            List<Menu> menuList = roleVO.getMenuList();
            for (Menu menu : menuList) {
                // 添加到授权信息
                info.addStringPermission(menu.getPerms());
            }
        }

        return info;
    }
}
